package demo.java.lang;

import org.junit.Test;

/**
 * 继承结构：Error和Exception都是继承于Throwable，RuntimeException继承自Exception。 Error和RuntimeException及其子类称为未检查异常（Unchecked
 * exception），其它异常成为受检查异常（Checked Exception）。
 * 
 *
 */
public class ThrowableDemo {

    /**
     * Error类一般是指与虚拟机相关的问题，如系统崩溃，虚拟机错误，内存空间不足，方法调用栈溢出等。 如java.lang.StackOverFlowError和Java.lang.OutOfMemoryError。
     * 对于这类错误，Java编译器不去检查他们。对于这类错误的导致的应用程序中断，仅靠程序本身无法恢复和预防，遇到这样的错误，建议让程序终止。
     */
    public void error() {
        Throwable error = new Error();
    }

    /**
     * Exception类表示程序可以处理的异常，可以捕获且可能恢复。遇到这类异常，应该尽可能处理异常，使程序恢复运行，而不应该随意终止异常。
     */
    public void exception() {
        Throwable exception = new Exception();
        Exception runtimeException = new RuntimeException();
    }

    /**
     * 推断main方法
     * @return
     */
    @Test
    private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        } catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

    @Test
    public void tryCatch() {
        for (int i = 0; i < 10; i++) {
            try {
                if (i % 2 == 1) {
                    System.out.println(i);
                } else {
                    throw new IllegalArgumentException();
                }
            } catch (Exception e) {
                System.out.println("IllegalArgumentException");
                continue;
            }
            System.out.println("hello.");
        }
    }

    /**
     * <li>1、不管是否有异常产生，finally块中代码都会执行；
     * <li>2、当try和catch中有return语句时，finally块仍然会执行；
     * <li>3、finally是在return后面的表达式运算后执行的，所以函数返回值是在finally执行前确定的。无论finally中的代码怎么样，返回的值都不会改变，仍然是之前return语句中保存的值；
     * <li>4、finally中最好不要包含return，否则程序会提前退出，返回值不是try或catch中保存的返回值。
     */
    @Test
    public void tryCatchFinally() {
        int i = test();
        System.out.println(i);
        String a = null;
        try {
            System.out.println("try block.");
            System.out.println(a.indexOf("b"));
            throw new Exception("throwException.");
        } catch (Exception e) {
            System.out.println("catch block.");
            System.out.println(e);
            return;
        } finally {
            System.out.println("finally block.");
        }
        // System.out.println("end.");
    }

    static int test() {
        int x = 1;
        try {
            x++;
            return x;
        } catch (Exception e) {
            return x;
        } finally {
            ++x;
        }
    }
}
